package com.uaroadshow.finale.web.controller.api;

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import com.demo2do.core.entity.exception.BusinessException;
import com.demo2do.core.entity.result.HttpResult;
import com.demo2do.core.utils.DateFormatUtils;
import com.demo2do.core.utils.JsonUtils;
import com.demo2do.core.wechat.entity.cfg.JsConfig;
import com.uaroadshow.entity.trade.Order;
import com.uaroadshow.entity.trade.PaymentRequest;
import com.uaroadshow.entity.user.User;
import com.uaroadshow.finale.handler.SmsHandler;
import com.uaroadshow.finale.processor.WechatProcessor;
import com.uaroadshow.finale.service.DataService;
import com.uaroadshow.finale.service.OrderService;

/**
 *
 * @author Ark
 *
 */
@RestController
@RequestMapping("/api/payments")
public class PaymentApiController {
    
    private static final Logger logger = LoggerFactory.getLogger(PaymentApiController.class);
    
    @Autowired
    private WechatProcessor     wechatProcessor;
    
    @Autowired
    private OrderService orderService;
    
    @Autowired
    @Qualifier("dataService")
    private DataService<User> userService;
    
    @Autowired
    @Qualifier("dataService")
    private DataService<PaymentRequest> paymentRequestService;
    
    @Autowired
    private SmsHandler smsHandler;
    
    /**
     * 支付
     * 
     * @param orderId
     * @param unionid
     * @param request
     * @return
     */
    @RequestMapping(value = "/pay", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public HttpResult onPay(@RequestParam("orderId") Long orderId,
                            @RequestParam("unionid") String unionid,
                            @RequestParam("currentUrl") String currentUrl,
                            HttpServletRequest request) {

        HttpResult httpResult = new HttpResult();

        try {
            
            JsConfig jsConfig = wechatProcessor.generateJsConfig(currentUrl);
            
            String xRealIpHeader = request.getHeader("X-Real-IP"); // Only available after NGINX redirect
            String remoteIp = StringUtils.isBlank(xRealIpHeader) ? request.getRemoteAddr() : xRealIpHeader;
            logger.trace("#onPay() - Get remote IP address [{}].", remoteIp);
            
            User user = userService.load(User.class, "unionid", unionid);
            
            Map<String, Object> payConfig = orderService.pay(orderId, user, remoteIp);

            httpResult.success().data("jsConfig", jsConfig)
                                .data("payConfig", payConfig)
                                .message("支付成功");
            
        } catch (BusinessException e) {
            logger.error("#onPay() - occurs error, business exception=[{}]", e);
            httpResult.fail(e.getCode()).message(e.getMessage());
        } catch (Exception e) {
            logger.error("#onPay() - occurs error, exception=[{}]", e);
            httpResult.fail("500").message("支付失败");
        }
        
        return httpResult;
        
    }
    
    /**
     * 支付回调
     * 
     * @param body
     * @param request
     * @return
     */
    @RequestMapping(value = "/callback", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    public @ResponseBody HttpResult onPaid(@RequestBody String body,
                                           HttpServletRequest request) {
        
        HttpResult httpResult = new HttpResult();
        
        try {
            
            Map<String, Object> params = JsonUtils.parse(body);
            logger.trace("#onPaid - Get rquest number [{}], order number [{}], amount [{}], pay time [{}], channel [{}].", 
                    params.get("requestNo"), params.get("orderNo"), params.get("transactionCode"), params.get("amount"), params.get("paymentTime"));
            
            // 1.1 validate payment request
            String requestCode = params.get("requestNo").toString();
            PaymentRequest paymentRequest = paymentRequestService.load(PaymentRequest.class, "code", requestCode);
            if(paymentRequest == null) {
                throw new BusinessException("支付回调数据错误");
            }
            
            // 1.2 validate payment request & order code
            String orderCode = params.get("orderNo").toString();
            if(!StringUtils.equalsIgnoreCase(orderCode, paymentRequest.getOrderCode())) {
                throw new BusinessException("支付回调数据异常");
            }
            
            // 2. do pay order
            String payCode = params.get("transactionCode").toString();
            String payTime = params.get("paymentTime").toString();
            
            Order order = orderService.paid(paymentRequest, orderCode, payCode, payTime);
            
            // 3. send message
            String mobile = order.getUser().getMobile();
            String productName = order.getProduct().getName();
            String time = com.demo2do.core.utils.StringUtils.connect(DateFormatUtils.format(order.getProduct().getStartTime(), "HH:mm"), " ~ " + DateFormatUtils.format(order.getProduct().getEndTime(), "HH:mm"));
            smsHandler.sendMessage(mobile, "【2018健身精英训练营】您已成功购买[" + productName + "]课程，时间：2018年11月17日" + time + "，地点：上海市静安区常德路800号 800秀。请提前三十分钟到活动现场出示购买凭证签到领装。订单详情及购买凭证请至活动页面>个人中心查看。");
            
            httpResult.success().message("支付回调成功");
            
            // check order & update order, product things
            logger.trace("#onPaid() - Synchronizing order with result [{}] !!!!!!!!", httpResult.getMessage());
            
        } catch (BusinessException e) {
            logger.error("#onPaid() - occurs error, business exception=[{}]", e);
            httpResult.fail("500").message(e.getMessage());
        } catch (Exception e) {
            logger.error("#onPaid() - occurs error, exception=[{}]", e);
            httpResult.fail("500").message("支付回调失败");
        }
        
        return httpResult;
        
    }
    
}
